# step3_pca.py
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler

print("=== 步骤3: PCA降维实现 ===")

# 定义列名
column_names = ['class', 'alcohol', 'malic_acid', 'ash', 'alcalinity_of_ash', 
                'magnesium', 'total_phenols', 'flavanoids', 'nonflavanoid_phenols',
                'proanthocyanins', 'color_intensity', 'hue', 'od280/od315', 'proline']

try:
    # 读取并预处理数据（与步骤2相同）
    print("正在加载和预处理数据...")
    wine_data = pd.read_csv('wine.data', header=None, names=column_names)
    
    # 筛选类别1和2的数据
    filtered_data = wine_data[wine_data['class'].isin([1, 2])].copy()
    X = filtered_data.drop('class', axis=1)
    y = filtered_data['class']
    
    # 数据标准化
    scaler = StandardScaler()
    X_scaled = scaler.fit_transform(X)
    
    print(f"数据预处理完成！")
    print(f"标准化后的数据形状: {X_scaled.shape}")

    # 手动实现PCA类
    class SimplePCA:
        def __init__(self, n_components=2):
            self.n_components = n_components
            self.components = None
            self.mean = None
            self.explained_variance = None
            
        def fit(self, X):
            # 1. 计算均值
            self.mean = np.mean(X, axis=0)
            X_centered = X - self.mean
            
            # 2. 计算协方差矩阵
            cov_matrix = np.cov(X_centered, rowvar=False)
            print(f"   协方差矩阵形状: {cov_matrix.shape}")
            
            # 3. 计算特征值和特征向量
            eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
            
            # 4. 按特征值大小排序（降序）
            sorted_indices = np.argsort(eigenvalues)[::-1]
            self.components = eigenvectors[:, sorted_indices[:self.n_components]]
            
            # 保存解释方差
            self.explained_variance = eigenvalues[sorted_indices[:self.n_components]]
            total_variance = np.sum(eigenvalues)
            self.explained_variance_ratio = self.explained_variance / total_variance
            
            print(f"   前{self.n_components}个主成分的解释方差: {self.explained_variance}")
            print(f"   前{self.n_components}个主成分的解释方差比例: {self.explained_variance_ratio}")
            print(f"   累计解释方差比例: {np.sum(self.explained_variance_ratio):.4f}")
            
            return self
        
        def transform(self, X):
            X_centered = X - self.mean
            return np.dot(X_centered, self.components)
        
        def fit_transform(self, X):
            self.fit(X)
            return self.transform(X)

    # 应用PCA
    print("\n开始PCA降维...")
    pca = SimplePCA(n_components=2)
    X_pca = pca.fit_transform(X_scaled)

    print(f"\nPCA降维完成！")
    print(f"降维后的数据形状: {X_pca.shape}")
    
    # 显示PCA结果
    print("\n PCA降维结果（前15个样本）:")
    print("样本编号 | 原始类别 | PCA特征1 | PCA特征2")
    print("-" * 50)
    
    for i in range(min(15, len(X_pca))):
        print(f"{i+1:6} | {y.iloc[i]:8} | {X_pca[i, 0]:8.4f} | {X_pca[i, 1]:8.4f}")

    # 保存PCA结果
    pca_results = pd.DataFrame({
        'class': y.values,
        'PCA_1': X_pca[:, 0],
        'PCA_2': X_pca[:, 1]
    })
    pca_results.to_csv('wine_pca_results.csv', index=False)
    print(f"\nPCA结果已保存到: wine_pca_results.csv")
    
    # 可视化PCA结果
    print("\n生成PCA可视化图...")
    plt.figure(figsize=(10, 6))
    
    # 为不同类别设置不同颜色和标记
    colors = ['red', 'blue']
    markers = ['o', 's']
    labels = ['Class 1', 'Class 2']
    
    for i, class_label in enumerate([1, 2]):
        mask = (y == class_label)
        plt.scatter(X_pca[mask, 0], X_pca[mask, 1], 
                   c=colors[i], marker=markers[i], 
                   label=labels[i], alpha=0.7, s=50)
    
    plt.xlabel('Principal Component 1')
    plt.ylabel('Principal Component 2')
    plt.title('PCA Projection of Wine Data (Classes 1 & 2)')
    plt.legend()
    plt.grid(True, alpha=0.3)
    
    # 添加一些统计信息到图上
    plt.text(0.05, 0.95, f'Explained Variance Ratio:\nPC1: {pca.explained_variance_ratio[0]:.3f}\nPC2: {pca.explained_variance_ratio[1]:.3f}', 
             transform=plt.gca().transAxes, verticalalignment='top',
             bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
    
    plt.tight_layout()
    plt.savefig('pca_visualization.png', dpi=300, bbox_inches='tight')
    plt.show()
    
    print("✅ 可视化图已保存为: pca_visualization.png")
    
    # 显示PCA的统计信息
    print("\nPCA统计信息:")
    print(f"主成分1的解释方差: {pca.explained_variance[0]:.4f}")
    print(f"主成分2的解释方差: {pca.explained_variance[1]:.4f}")
    print(f"主成分1的解释方差比例: {pca.explained_variance_ratio[0]:.4f}")
    print(f"主成分2的解释方差比例: {pca.explained_variance_ratio[1]:.4f}")
    print(f"累计解释方差比例: {np.sum(pca.explained_variance_ratio):.4f}")
    
except Exception as e:
    print(f"出错: {e}")
    import traceback
    traceback.print_exc()

input("\n按 Enter 键继续下一步...")